/**
 * TTS语音合成助手 JavaScript
 */

class TTSApp {
    constructor() {
        this.ws = null;
        this.isConnected = false;
        this.audioBlob = null;
        this.audioUrl = null;
        this.synthesizeCount = 0;
        this.totalChars = 0;
        this.history = [];
        this.audioContext = null;
        this.currentAudio = null;
        this.reconnectAttempts = 0;
        this.heartbeatInterval = null;
        this.connectionCheckInterval = null;
        this.config = null; // 新增配置属性
        this.init();
    }

    init() {
        // 绑定事件
        this.bindEvents();
        
        // 初始化音频上下文
        this.initAudioContext();
        
        // 连接WebSocket
        this.connectWebSocket();
        
        // 加载系统信息
        this.loadSystemInfo();
        
        // 从本地存储加载历史记录
        this.loadHistory();
        
        // 更新字符计数
        this.updateCharCount();
        
        // 获取配置信息并填充音色列表（确保DOM加载完成后执行）
        if (document.readyState === 'loading') {
            document.addEventListener('DOMContentLoaded', () => {
                this.fetchConfig();
            });
        } else {
            // DOM已加载完成，延迟执行以确保所有元素已准备就绪
            setTimeout(() => {
                this.fetchConfig();
            }, 100);
        }
    }

    bindEvents() {
        const textInput = document.getElementById('textInput');
        const synthesizeBtn = document.getElementById('synthesizeBtn');
        const clearBtn = document.getElementById('clearBtn');
        const speedSlider = document.getElementById('speedSlider');
        const volumeSlider = document.getElementById('volumeSlider');
        
        // 合成按钮点击事件
        synthesizeBtn.addEventListener('click', () => this.synthesizeText());
        
        // 清空按钮点击事件
        clearBtn.addEventListener('click', () => this.clearInput());
        
        // 文本输入事件
        textInput.addEventListener('input', () => {
            this.updateCharCount();
            this.autoResize();
        });
        
        // 滑块事件
        speedSlider.addEventListener('input', () => {
            document.getElementById('speedValue').textContent = speedSlider.value + 'x';
        });
        
        volumeSlider.addEventListener('input', () => {
            document.getElementById('volumeValue').textContent = volumeSlider.value + 'x';
        });
        
        // 音频元素事件
        const audioElement = document.getElementById('audioElement');
        audioElement.addEventListener('loadedmetadata', () => {
            this.updateAudioInfo();
        });
        
        audioElement.addEventListener('ended', () => {
            this.updateAudioInfo();
        });
        
        // 初始化自动调整大小
        this.autoResize();
    }

    initAudioContext() {
        try {
            window.AudioContext = window.AudioContext || window.webkitAudioContext;
            this.audioContext = new AudioContext();
        } catch (error) {
            console.warn('Web Audio API not supported:', error);
        }
    }

    connectWebSocket() {
        // 如果已有连接，先关闭
        if (this.ws) {
            this.ws.close();
            this.ws = null;
        }
        
        this.reconnectAttempts = (this.reconnectAttempts || 0);
        const maxReconnectAttempts = 10;
        
        if (this.reconnectAttempts >= maxReconnectAttempts) {
            this.updateConnectionStatus('error', '连接失败（已达最大重试次数）');
            this.showNotification('WebSocket连接失败，请检查网络或刷新页面', 'error');
            return;
        }
        
        try {
            this.updateConnectionStatus('connecting', '连接中...');
            
            // 构建WebSocket URL - 支持局域网访问
            const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
            const wsUrl = `${protocol}//${window.location.host}/ws`;
            
            console.log(`尝试连接WebSocket: ${wsUrl} (第${this.reconnectAttempts + 1}次)`);
            this.ws = new WebSocket(wsUrl);
            
            // 设置连接超时
            const connectionTimeout = setTimeout(() => {
                if (this.ws && this.ws.readyState === WebSocket.CONNECTING) {
                    console.warn('WebSocket连接超时，关闭连接');
                    this.ws.close();
                }
            }, 10000); // 10秒超时
            
            this.ws.onopen = () => {
                clearTimeout(connectionTimeout);
                this.isConnected = true;
                this.reconnectAttempts = 0; // 重置重连计数
                this.updateConnectionStatus('connected', '已连接');
                this.showNotification('WebSocket连接成功', 'success');
                console.log('WebSocket连接成功');
                
                // 启动心跳机制
                this.startHeartbeat();
                this.startConnectionCheck();
            };
            
            this.ws.onmessage = (event) => {
                this.handleWebSocketMessage(event);
            };
            
            this.ws.onclose = (event) => {
                clearTimeout(connectionTimeout);
                this.isConnected = false;
                
                // 停止心跳和连接检查
                this.stopHeartbeat();
                this.stopConnectionCheck();
                
                console.log(`WebSocket连接关闭: code=${event.code}, reason=${event.reason}`);
                
                if (event.code === 1000) {
                    // 正常关闭，不重连
                    this.updateConnectionStatus('disconnected', '连接已关闭');
                    return;
                }
                
                this.updateConnectionStatus('disconnected', '连接断开');
                
                // 如果不是用户主动关闭，则尝试重连
                if (!event.wasClean) {
                    this.reconnectAttempts++;
                    const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts - 1), 30000); // 指数退避，最大30秒
                    
                    this.updateConnectionStatus('reconnecting', `重连中... (${delay/1000}秒后第${this.reconnectAttempts + 1}次尝试)`);
                    
                    setTimeout(() => {
                        if (!this.isConnected) {
                            this.connectWebSocket();
                        }
                    }, delay);
                }
            };
            
            this.ws.onerror = (error) => {
                clearTimeout(connectionTimeout);
                this.updateConnectionStatus('error', '连接错误');
                console.error('WebSocket error:', error);
            };
            
        } catch (error) {
            this.updateConnectionStatus('error', '连接失败');
            this.showNotification('无法建立WebSocket连接', 'error');
            console.error('WebSocket connection failed:', error);
            
            // 延迟重试
            setTimeout(() => {
                if (!this.isConnected) {
                    this.reconnectAttempts++;
                    this.connectWebSocket();
                }
            }, 2000);
        }
    }

    handleWebSocketMessage(event) {
        try {
            const data = JSON.parse(event.data);
            
            switch (data.type) {
                case 'synthesis_progress':
                    this.updateProgress(data.progress);
                    break;
                    
                case 'synthesis_complete':
                    this.handleSynthesisComplete(data.audio_data);
                    break;
                    
                case 'synthesis_error':
                    this.handleSynthesisError(data.error);
                    break;
                    
                case 'system_info':
                    this.updateSystemInfo(data.info);
                    break;
                    
                case 'pong':
                    // 收到心跳响应，连接正常
                    console.log('收到心跳响应，连接正常');
                    break;
                    
                default:
                    console.log('Unknown message type:', data.type);
            }
        } catch (error) {
            console.error('Error parsing WebSocket message:', error);
        }
    }

    async synthesizeText() {
        const textInput = document.getElementById('textInput');
        const text = textInput.value.trim();
        
        if (!text) {
            this.showNotification('请输入要合成的文本', 'warning');
            return;
        }
        
        // 检查文本语言和音色匹配
        if (!this.checkLanguageCompatibility(text)) {
            return;
        }
        
        if (!this.isConnected) {
            this.showNotification('WebSocket未连接，请稍后重试', 'error');
            return;
        }
        
        // 显示加载状态
        this.showLoading(true);
        
        // 获取参数
        const voice = document.getElementById('voiceSelect').value;
        const speed = parseFloat(document.getElementById('speedSlider').value);
        const volume = parseFloat(document.getElementById('volumeSlider').value);
        const format = document.getElementById('formatSelect').value;
        
        try {
            // 发送合成请求
            const request = {
                type: 'synthesize',
                text: text,
                voice: voice,
                speed: speed,
                volume: volume,
                format: format
            };
            
            this.ws.send(JSON.stringify(request));
            
            // 更新统计
            this.synthesizeCount++;
            this.totalChars += text.length;
            this.updateStats();
            
            // 添加到历史记录
            this.addToHistory(text, voice);
            
        } catch (error) {
            this.hideLoading();
            this.showNotification('发送合成请求失败', 'error');
            console.error('Synthesis request failed:', error);
        }
    }

    checkLanguageCompatibility(text) {
        if (!this.config || !this.config.voices) {
            console.warn('配置或音色列表未加载，跳过语言兼容性检查。');
            return true;
        }

        const selectedVoiceId = document.getElementById('voiceSelect').value;
        const selectedVoice = this.getVoiceById(selectedVoiceId);

        if (!selectedVoice) {
            this.showNotification('未找到选中的音色信息，请刷新页面重试。', 'error');
            return false;
        }

        // 检测文本中的语言
        const containsHiragana = /[\u3040-\u309f]/.test(text);
        const containsKatakana = /[\u30a0-\u30ff]/.test(text);
        const containsJapanese = containsHiragana || containsKatakana;
        const containsEnglish = /[a-zA-Z]/.test(text);
        
        // 如果包含假名，则认为是日语，不再检测中文
        // 否则检测中文汉字
        const containsChinese = !containsJapanese && /[\u4e00-\u9fa5]/.test(text);
        
        // 检查音色支持的语言
        const supportedLanguages = selectedVoice.languages;
        const voiceSupportsChinese = supportedLanguages.includes('zh');
        const voiceSupportsJapanese = supportedLanguages.includes('ja');
        const voiceSupportsEnglish = supportedLanguages.includes('en-US') || supportedLanguages.includes('en-GB');

        // 检查语言兼容性
        if (containsChinese && !voiceSupportsChinese) {
            this.showNotification(`文本包含中文字符，但选中的音色 "${selectedVoice.name}" 不支持中文。请选择支持中文的音色。`, 'warning');
            return false;
        }

        if (containsJapanese && !voiceSupportsJapanese) {
            this.showNotification(`文本包含日语字符，但选中的音色 "${selectedVoice.name}" 不支持日语。请选择支持日语的音色。`, 'warning');
            return false;
        }

        if (containsEnglish && !voiceSupportsEnglish && !containsChinese && !containsJapanese) {
            this.showNotification(`文本包含英语字符，但选中的音色 "${selectedVoice.name}" 不支持英语。请选择支持英语的音色。`, 'warning');
            return false;
        }
        
        return true;
    }

    getVoiceById(voiceId) {
        if (!this.config || !this.config.voices) {
            return null;
        }
        for (const group of this.config.voices) {
            for (const option of group.options) {
                if (option.id === voiceId) {
                    return option;
                }
            }
        }
        return null;
    }

    handleSynthesisComplete(audioData) {
        this.hideLoading();
        
        try {
            // 将Base64转换为Blob
            const byteCharacters = atob(audioData);
            const byteNumbers = new Array(byteCharacters.length);
            
            for (let i = 0; i < byteCharacters.length; i++) {
                byteNumbers[i] = byteCharacters.charCodeAt(i);
            }
            
            const byteArray = new Uint8Array(byteNumbers);
            const format = document.getElementById('formatSelect').value;
            const mimeType = this.getMimeType(format);
            
            // 释放旧的音频URL
            if (this.audioUrl) {
                URL.revokeObjectURL(this.audioUrl);
            }
            
            this.audioBlob = new Blob([byteArray], { type: mimeType });
            this.audioUrl = URL.createObjectURL(this.audioBlob);
            
            // 设置音频元素
            const audioElement = document.getElementById('audioElement');
            audioElement.src = this.audioUrl;
            
            // 重置音频元素状态
            audioElement.load();
            audioElement.currentTime = 0;
            
            // 显示音频控件
            document.getElementById('audioPlayerContainer').style.display = 'block';
            document.getElementById('audioControls').style.display = 'flex';
            
            this.showNotification('语音合成成功', 'success');
            
        } catch (error) {
            this.showNotification('处理音频数据失败', 'error');
            console.error('Audio processing failed:', error);
        }
    }

    handleSynthesisError(error) {
        this.hideLoading();
        this.showNotification(`合成失败: ${error}`, 'error');
        console.error('Synthesis error:', error);
    }

    updateProgress(progress) {
        const loadingProgress = document.getElementById('loadingProgress');
        loadingProgress.textContent = `${progress}%`;
    }

    getMimeType(format) {
        const mimeTypes = {
            'mp3': 'audio/mpeg',
            'wav': 'audio/wav',
            'flac': 'audio/flac'
        };
        return mimeTypes[format] || 'audio/mpeg';
    }

    clearInput() {
        const textInput = document.getElementById('textInput');
        textInput.value = '';
        this.updateCharCount();
        this.autoResize();
        textInput.focus();
    }

    loadDemoText(text) {
        const textInput = document.getElementById('textInput');
        textInput.value = text;
        this.updateCharCount();
        this.autoResize();
        textInput.focus();
        
        // 智能选择合适的音色
        this.autoSelectVoiceForText(text);
    }

    autoSelectVoiceForText(text) {
        if (!this.config || !this.config.voices) {
            return;
        }

        // 检测文本语言
        const containsHiragana = /[\u3040-\u309f]/.test(text);
        const containsKatakana = /[\u30a0-\u30ff]/.test(text);
        const containsJapanese = containsHiragana || containsKatakana;
        const containsEnglish = /[a-zA-Z]/.test(text);
        
        // 如果包含假名，则认为是日语，不再检测中文
        // 否则检测中文汉字
        const containsChinese = !containsJapanese && /[\u4e00-\u9fa5]/.test(text);
        
        const voiceSelect = document.getElementById('voiceSelect');
        const currentVoiceId = voiceSelect.value;
        const currentVoice = this.getVoiceById(currentVoiceId);
        
        // 如果当前音色已经支持文本语言，则不切换
        if (currentVoice) {
            const supportsChinese = currentVoice.languages.includes('zh');
            const supportsJapanese = currentVoice.languages.includes('ja');
            const supportsEnglish = currentVoice.languages.includes('en-US') || currentVoice.languages.includes('en-GB');
            
            if ((containsChinese && supportsChinese) ||
                (containsJapanese && supportsJapanese) ||
                (containsEnglish && supportsEnglish && !containsChinese && !containsJapanese)) {
                return; // 当前音色支持，无需切换
            }
        }
        
        // 寻找合适的音色
        let targetVoiceId = null;
        
        if (containsJapanese) {
            // 优先选择日语音色
            targetVoiceId = this.findVoiceBySupportedLanguage('ja');
        } else if (containsChinese) {
            // 选择中文音色
            targetVoiceId = this.findVoiceBySupportedLanguage('zh');
        } else if (containsEnglish) {
            // 选择英文音色
            targetVoiceId = this.findVoiceBySupportedLanguage('en-US') || this.findVoiceBySupportedLanguage('en-GB');
        }
        
        if (targetVoiceId && targetVoiceId !== currentVoiceId) {
            voiceSelect.value = targetVoiceId;
            this.showNotification(`已自动切换到合适的音色`, 'info');
        }
    }

    findVoiceBySupportedLanguage(language) {
        if (!this.config || !this.config.voices) {
            return null;
        }
        
        for (const group of this.config.voices) {
            for (const option of group.options) {
                if (option.languages.includes(language)) {
                    return option.id;
                }
            }
        }
        return null;
    }

    updateCharCount() {
        const textInput = document.getElementById('textInput');
        const charCount = document.getElementById('charCount');
        const length = textInput.value.length;
        charCount.textContent = `${length}/5000`;
        
        if (length > 4500) {
            charCount.style.color = '#e74c3c';
        } else if (length > 3500) {
            charCount.style.color = '#f39c12';
        } else {
            charCount.style.color = '#6c757d';
        }
    }

    autoResize() {
        const textInput = document.getElementById('textInput');
        textInput.style.height = 'auto';
        textInput.style.height = Math.min(textInput.scrollHeight, 300) + 'px';
    }

    updateConnectionStatus(status, text) {
        const statusDot = document.getElementById('statusDot');
        const statusText = document.getElementById('statusText');
        const connectionInfo = document.getElementById('connectionInfo');
        
        statusDot.className = 'status-dot';
        if (status === 'connected') {
            statusDot.classList.add('connected');
        } else if (status === 'error') {
            statusDot.classList.add('error');
        }
        
        statusText.textContent = text;
        
        // 如果连接状态有问题，显示重连按钮
        if (status === 'error' || status === 'disconnected' || status === 'reconnecting') {
            connectionInfo.innerHTML = `${text} <button onclick="manualReconnect()" class="reconnect-btn">手动重连</button>`;
        } else {
            connectionInfo.textContent = text;
        }
    }

    updateAudioInfo() {
        const audioElement = document.getElementById('audioElement');
        const audioInfo = document.getElementById('audioInfo');
        
        if (audioElement.duration) {
            const duration = Math.round(audioElement.duration);
            const currentTime = Math.round(audioElement.currentTime);
            audioInfo.textContent = `时长: ${duration}秒 | 当前进度: ${currentTime}秒`;
        } else {
            audioInfo.textContent = '音频已加载';
        }
    }

    updateStats() {
        document.getElementById('synthesizeCount').textContent = this.synthesizeCount;
        document.getElementById('totalChars').textContent = this.totalChars;
        
        const avgDuration = this.synthesizeCount > 0 ? 
            Math.round(this.totalChars / 10) : 0; // 简单估算
        document.getElementById('avgDuration').textContent = avgDuration + '秒';
    }

    async fetchConfig() {
        try {
            const response = await fetch('/config');
            if (!response.ok) {
                throw new Error(`HTTP error! status: ${response.status}`);
            }
            this.config = await response.json();
            console.log('配置加载成功:', this.config);

            // 填充音色选择下拉框
            this.populateVoiceSelect(this.config.voices, this.config.default_voice);
            
            // 更新系统信息
            this.updateSystemInfo(this.config);

            // 更新文本输入框的最大长度
            const textInput = document.getElementById('textInput');
            textInput.maxLength = this.config.max_text_length;
            this.updateCharCount();

        } catch (error) {
            console.error('加载配置失败:', error);
            this.showNotification('加载配置失败，部分功能可能受限', 'error');
        }
    }

    populateVoiceSelect(voices, defaultVoice) {
        const voiceSelect = document.getElementById('voiceSelect');
        if (!voiceSelect) {
            console.error('找不到音色选择下拉框元素');
            return;
        }
        
        voiceSelect.innerHTML = ''; // 清空现有选项

        if (!voices || voices.length === 0) {
            const option = document.createElement('option');
            option.value = '';
            option.textContent = '无可用音色';
            voiceSelect.appendChild(option);
            voiceSelect.disabled = true;
            console.warn('没有可用的音色配置');
            return;
        }

        console.log('开始填充音色选择框，音色组数量:', voices.length);

        voices.forEach((group, groupIndex) => {
            if (!group.group || !group.options || !Array.isArray(group.options)) {
                console.warn(`跳过无效的音色组 ${groupIndex}:`, group);
                return;
            }

            const optgroup = document.createElement('optgroup');
            optgroup.label = group.group;
            
            group.options.forEach((voiceOption, optionIndex) => {
                if (!voiceOption.id || !voiceOption.name) {
                    console.warn(`跳过无效的音色选项 ${groupIndex}-${optionIndex}:`, voiceOption);
                    return;
                }

                const option = document.createElement('option');
                option.value = voiceOption.id;
                
                // 格式化语言显示
                const languageDisplay = (voiceOption.languages || []).map(lang => {
                    if (lang === 'zh') return '中文';
                    if (lang === 'en-US') return '美式英语';
                    if (lang === 'en-GB') return '英式英语';
                    return lang;
                }).join('、');
                
                option.textContent = `${voiceOption.name}${languageDisplay ? ` (支持: ${languageDisplay})` : ''}`;
                optgroup.appendChild(option);
            });

            if (optgroup.children.length > 0) {
                voiceSelect.appendChild(optgroup);
            }
        });

        // 设置默认音色
        if (defaultVoice) {
            voiceSelect.value = defaultVoice;
            console.log('设置默认音色:', defaultVoice);
        }
        
        voiceSelect.disabled = false;
        console.log('音色选择框填充完成，总选项数:', voiceSelect.querySelectorAll('option').length);
    }

    loadSystemInfo() {
        // 此方法现在主要用于初始化，实际信息由fetchConfig获取后更新
        const audioProcessingElement = document.getElementById('audioProcessingInfo');
        if (audioProcessingElement) {
            audioProcessingElement.textContent = '检测中...';
        }
        
        const maxTextLengthElement = document.getElementById('maxTextLengthInfo');
        if (maxTextLengthElement) {
            maxTextLengthElement.textContent = '加载中...';
        }
    }

    updateSystemInfo(config) {
        if (config) {
            const audioProcessingElement = document.getElementById('audioProcessingInfo');
            if (audioProcessingElement) {
                audioProcessingElement.textContent = config.audio_processing ? '✅ 已启用' : '❌ 未启用';
            }
            
            const maxTextLengthElement = document.getElementById('maxTextLengthInfo');
            if (maxTextLengthElement) {
                maxTextLengthElement.textContent = `${config.max_text_length}字符`;
            }
        }
    }

    addToHistory(text, voice) {
        const historyItem = {
            id: Date.now(),
            text: text,
            voice: voice,
            timestamp: new Date().toLocaleString('zh-CN')
        };
        
        this.history.unshift(historyItem);
        
        // 限制历史记录数量
        if (this.history.length > 10) {
            this.history = this.history.slice(0, 10);
        }
        
        // 保存到本地存储
        this.saveHistory();
        this.updateHistoryDisplay();
    }

    loadHistory() {
        try {
            const saved = localStorage.getItem('tts_history');
            if (saved) {
                this.history = JSON.parse(saved);
                this.updateHistoryDisplay();
            }
        } catch (error) {
            console.error('Failed to load history:', error);
        }
    }

    saveHistory() {
        try {
            localStorage.setItem('tts_history', JSON.stringify(this.history));
        } catch (error) {
            console.error('Failed to save history:', error);
        }
    }

    updateHistoryDisplay() {
        const historyList = document.getElementById('historyList');
        historyList.innerHTML = '';
        
        if (this.history.length === 0) {
            historyList.innerHTML = '<div class="empty-history">暂无合成记录</div>';
            return;
        }
        
        this.history.forEach(item => {
            const historyDiv = document.createElement('div');
            historyDiv.className = 'history-item';
            historyDiv.onclick = () => {
                document.getElementById('voiceSelect').value = item.voice;
                this.loadDemoText(item.text);
            };
            
            historyDiv.innerHTML = `
                <div class="history-text">${this.truncateText(item.text, 50)}</div>
                <div class="history-time">${item.voice} · ${item.timestamp}</div>
            `;
            
            historyList.appendChild(historyDiv);
        });
    }

    truncateText(text, maxLength) {
        if (text.length <= maxLength) {
            return text;
        }
        return text.substring(0, maxLength) + '...';
    }

    playAudio() {
        const audioElement = document.getElementById('audioElement');
        if (this.audioUrl) {
            audioElement.play().catch(error => {
                this.showNotification('播放失败', 'error');
                console.error('Audio play failed:', error);
            });
        }
    }

    pauseAudio() {
        const audioElement = document.getElementById('audioElement');
        audioElement.pause();
    }

    downloadAudio() {
        if (!this.audioBlob || !this.audioUrl) {
            this.showNotification('没有可下载的音频', 'warning');
            return;
        }
        
        const format = document.getElementById('formatSelect').value;
        const timestamp = new Date().toISOString().slice(0, 19).replace(/:/g, '-');
        const filename = `tts_${timestamp}.${format}`;
        
        const a = document.createElement('a');
        a.href = this.audioUrl;
        a.download = filename;
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        
        this.showNotification('音频下载已开始', 'success');
    }

    showLoading(show) {
        const loadingOverlay = document.getElementById('loadingOverlay');
        if (show) {
            loadingOverlay.style.display = 'flex';
        } else {
            loadingOverlay.style.display = 'none';
        }
    }

    hideLoading() {
        this.showLoading(false);
    }

    showNotification(message, type = 'info') {
        const notification = document.getElementById('notification');
        const notificationText = document.getElementById('notificationText');
        
        notificationText.textContent = message;
        notification.className = `notification ${type}`;
        notification.style.display = 'flex';
        
        // 3秒后自动隐藏
        setTimeout(() => {
            this.hideNotification();
        }, 3000);
    }

    hideNotification() {
        const notification = document.getElementById('notification');
        notification.style.display = 'none';
    }
    
    // 心跳机制相关方法
    startHeartbeat() {
        this.stopHeartbeat(); // 确保之前的心跳已停止
        
        this.heartbeatInterval = setInterval(() => {
            if (this.ws && this.ws.readyState === WebSocket.OPEN) {
                try {
                    // 发送心跳ping消息
                    this.ws.send(JSON.stringify({
                        type: 'ping',
                        timestamp: Date.now()
                    }));
                } catch (error) {
                    console.error('发送心跳失败:', error);
                    this.handleConnectionLost();
                }
            } else {
                this.handleConnectionLost();
            }
        }, 30000); // 每30秒发送一次心跳
    }
    
    stopHeartbeat() {
        if (this.heartbeatInterval) {
            clearInterval(this.heartbeatInterval);
            this.heartbeatInterval = null;
        }
    }
    
    // 连接状态检查
    startConnectionCheck() {
        this.stopConnectionCheck(); // 确保之前的检查已停止
        
        this.connectionCheckInterval = setInterval(() => {
            if (!this.isConnected || !this.ws || this.ws.readyState !== WebSocket.OPEN) {
                console.warn('检测到连接异常，尝试重连');
                this.handleConnectionLost();
            }
        }, 10000); // 每10秒检查一次
    }
    
    stopConnectionCheck() {
        if (this.connectionCheckInterval) {
            clearInterval(this.connectionCheckInterval);
            this.connectionCheckInterval = null;
        }
    }
    
    // 处理连接丢失
    handleConnectionLost() {
        if (this.isConnected) {
            this.isConnected = false;
            this.stopHeartbeat();
            this.stopConnectionCheck();
            this.updateConnectionStatus('reconnecting', '连接丢失，重连中...');
            
            // 尝试重新连接
            setTimeout(() => {
                if (!this.isConnected) {
                    this.connectWebSocket();
                }
            }, 1000);
        }
    }
    
    // 手动重连方法
    manualReconnect() {
        console.log('用户手动重连');
        this.reconnectAttempts = 0; // 重置重连计数
        this.stopHeartbeat();
        this.stopConnectionCheck();
        
        if (this.ws) {
            this.ws.close();
        }
        
        this.connectWebSocket();
    }
    
    // 清除历史记录
    clearHistory() {
        if (this.history.length === 0) {
            this.showNotification('没有历史记录需要清除', 'info');
            return;
        }
        
        // 确认对话框
        if (confirm('确定要清除所有最近合成记录吗？此操作不可撤销。')) {
            this.history = [];
            this.saveHistory();
            this.updateHistoryDisplay();
            this.showNotification('历史记录已清除', 'success');
        }
    }
}

// 全局变量
let app;

// 页面加载完成后初始化应用
document.addEventListener('DOMContentLoaded', () => {
    app = new TTSApp();
});

// 全局函数供HTML调用
function synthesizeText() {
    app.synthesizeText();
}

function clearInput() {
    app.clearInput();
}

function loadDemoText(text) {
    app.loadDemoText(text);
}

function playAudio() {
    app.playAudio();
}

function pauseAudio() {
    app.pauseAudio();
}

function downloadAudio() {
    app.downloadAudio();
}

function hideNotification() {
    app.hideNotification();
}

function manualReconnect() {
    app.manualReconnect();
}

function clearHistory() {
    app.clearHistory();
}